package com.mtw.bbs.auth.utils;


import com.alibaba.fastjson.JSON;
import com.mtw.bbs.auth.pojo.PayloadData;
import com.mtw.bbs.common.core.constant.AuthConstant;
import com.mtw.bbs.common.core.enums.ResultCode;
import com.mtw.bbs.common.core.exception.AuthException;
import com.mtw.bbs.common.core.exception.BaseException;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.util.UUID;

import static com.mtw.bbs.common.core.constant.AuthConstant.*;


@Slf4j
@Component
public class JwtTokenUtil {


    /**
     * jwt token 密钥，主要用于token解析，签名验证
     */
    @Value("${security.jwt.signingKey:319726234@qq.com}")
    private String signingKey;


    /**
     * 创建jwt Token
     *
     * @param payloadData 负载信息
     * @param tokenType   token类型
     * @return token
     */
    public String crateJwtToken(PayloadData payloadData, String tokenType) {

        long currentTimeMillis = System.currentTimeMillis();
        payloadData.setJti(UUID.randomUUID().toString());
        payloadData.setExp(currentTimeMillis + (ACCESS_TOKEN_KEY.equals(tokenType) ? EXPIRE_TIME_MS : REFRESH_TIME_MS));
        payloadData.setIat(currentTimeMillis);
        payloadData.setSub(ACCESS_TOKEN_KEY.equals(tokenType) ? ACCESS_TOKEN_KEY : REFRESH_TOKEN_KEY);
        try {
            //构建JWS头
            JWSHeader jwsHeader = new JWSHeader.Builder(JWSAlgorithm.HS256).type(JOSEObjectType.JWT).build();
            //构建载荷
            Payload payload = new Payload(JSON.toJSONString(payloadData));
            //将JWS-header和payload封装成JWS对象中
            JWSObject jwsObject = new JWSObject(jwsHeader, payload);
            //创建HMAC签名器
            JWSSigner jwsSigner = new MACSigner(getSecret() + payloadData.getUsername());
            jwsObject.sign(jwsSigner);
            return jwsObject.serialize();
        } catch (JOSEException e) {
            log.error("jwt生成器异常", e);
            throw new BaseException("jwt生成器异常");
        }
    }

    private static String encrypt(String str, String encryptType) {
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance(encryptType);
            md.update(str.getBytes());
            byte[] encryptionKey = md.digest();
            StringBuilder builder = new StringBuilder();
            for (byte b : encryptionKey) {
                builder.append(String.format("%02X", b));
            }
            return builder.toString();
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }


    /**
     * 生成md5
     */
    public static String getMd5(String str) {
        return encrypt(str, "MD5");
    }

    /**
     * 生成秘钥
     */
    private String getSecret() {

        String encrypt = encrypt(signingKey, "SHA-256");
        if (encrypt == null) {
            return signingKey;
        }
        return encrypt;
    }


    /**
     * 从请求头中获取token
     *
     * @return token
     */
    public static String getTokenFromHeader(HttpServletRequest request) {
        // 先从header取值
        return request.getHeader(AuthConstant.AUTHORIZATION_KEY);
    }


    /**
     * 从请求头中获取服务间token
     *
     * @return token
     */
    public static String getServiceTokenFromHeader(HttpServletRequest request) {
        return request.getHeader(SERVICE_AUTH_KEY);
    }


    /**
     * 校验token
     */
    public boolean validateJwtToken(String token){

        PayloadData payloadData = getPayload(token);
        if (payloadData == null) {
            return false;
        }
        if (payloadData.getExp() <= System.currentTimeMillis()) {
            throw new AuthException(ResultCode.AUTH_EXP_ERROR.getCode(),"token已过期");
        }
        return true;
    }

    /**
     * 校验格式
     *
     * @param token token负载信息
     */
    public PayloadData getPayload(String token) {

        try {
            //从token中解析JWS对象
            JWSObject jwsObject = null;
            jwsObject = JWSObject.parse(token);
            String payload = jwsObject.getPayload().toString();
            PayloadData payloadData = JSON.parseObject(payload, PayloadData.class);
            //创建HMAC验证器
            JWSVerifier jwsVerifier = new MACVerifier(getSecret() + payloadData.getUsername());
            if (!jwsObject.verify(jwsVerifier)) {
                throw new BaseException("签名不合法!");
            }
            return payloadData;
        } catch (ParseException  | JOSEException e) {
            log.error("token校验出错",e);
            throw new AuthException(ResultCode.SERVICE_EXP.getCode(),"token校验出错");
        }

    }


}


